package org.zhao.nettydemos.protocol;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import lombok.extern.slf4j.Slf4j;
import org.zhao.nettydemos.echoServer.NettyEchoServerHandler;
import org.zhao.nettydemos.entity.JsonMsg;

import java.nio.charset.Charset;

/**
 * @Auther: xiaohui.zhao
 * @Date: 2021/9/16 17:43
 * @Description:
 */
@Slf4j
public class JsonServer {

    private final int serverPort;

    // 服务端引导类
    ServerBootstrap serverBootstrap = new ServerBootstrap();

    public JsonServer(int serverPort){
        this.serverPort = serverPort;
    }

    public void runServer(){

        EventLoopGroup bossLoopGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerLoopGroup = new NioEventLoopGroup();

        try{
            // 1. 设置反应器轮询组
            serverBootstrap.group(bossLoopGroup,workerLoopGroup);
            //2. 设置nio类型的通道
            serverBootstrap.channel(NioServerSocketChannel.class);
            //3. 设置监听端口
            serverBootstrap.localAddress(serverPort);
            // 4. 设置通道参数  , option方法用于给父通道设置一些与传输协议相关的选项
            // SO_KEEPALIVE 表示是否开启TCP底层心跳机制 ， true表示开启
            // 默认的心跳间隔时间是7200秒 ， 即2小时 ， 默认是关闭这个功能的
            serverBootstrap.option(ChannelOption.SO_KEEPALIVE,true);
            // netty4.1版本中默认的分配器就是 池化内存分配器
            // 设置父通道的缓冲区分配器
            serverBootstrap.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
            // 设置子通道的缓冲区分配器
            serverBootstrap.childOption(ChannelOption.ALLOCATOR,PooledByteBufAllocator.DEFAULT);
            /**
             * 父通道流水线不用装配的原因是 ： 父通道NioServerSocketChannel的内部业务处理是固定的 ，  接收到新连接后，创建子通道 ，然后初始化子通道
             */

            //5. 装配子通道流水线
            serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                // 有连接到达时会创建一个通道  , 在子通道创建后被执行 , 向子通道流水线增加业务处理器
                @Override
                protected void initChannel(SocketChannel ch){
                    // 流水线的职责 负责管理通道中的处理器 ， 向 子通道 传输通道流水线添加一个处理器
                    ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(1024,0,4,0,4));
                    ch.pipeline().addLast(new StringDecoder(Charset.forName("UTF-8")));
                    ch.pipeline().addLast(new JsonMsgDecoder());
                }
            });
            // 6. 开始绑定服务
            // 通过调用sync同步方法阻塞直到绑定成功
            ChannelFuture channelFuture = serverBootstrap.bind().sync();
            log.info("服务器启动成功 ， 监听端口"+channelFuture.channel().localAddress());
            //7. 等待通道关闭的异步任务结束 ， 服务监听通道会一直等待通道关闭的异步任务结束
            ChannelFuture closeFuture = channelFuture.channel().closeFuture();
            closeFuture.sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally{
            // 8. 关闭eventloopgroup
            // 释放掉所有资源 ， 包括创建的线程
            workerLoopGroup.shutdownGracefully();
            bossLoopGroup.shutdownGracefully();
        }

    }

    static class JsonMsgDecoder extends ChannelInboundHandlerAdapter{

        @Override
        public void channelRead(ChannelHandlerContext ctx,Object msg){
            String json = (String)msg;
            JsonMsg jsonMsg  = JsonMsg.parseFromJson(json);
            log.info("收到一个json格式的数据包 : "+jsonMsg);
        }
    }

    public static void main(String[] args) {
        new JsonServer(18899).runServer();
    }

}